package Model;

import java.util.ArrayList;


/**
 * This class represents an Intersecion object
 *
 * @author Matthew Page
 *         Date: 19/08/2010
 *         Time: 10:21:09 AM
 */
public class InterGrid {
    private final int MINHORLANES;
    private final int MAXHORLANES;
    private final int MINVERTLANES;
    private final int MAXVERTLANES;
    private final int MINPROB;
    private final int MAXPROB;

    private ArrayList<Car> cars;

    private char grid[][];
    private char carSymbol;
    private int vertColStart;
    private int vertRowStart;
    private int horColStart;
    private int horRowStart;

    private int numHorLanes;
    private int numVertLanes;
    private int carLengthsPerLane;
    private int westVertBound;
    private int eastVertBound;
    private int northHorBound;
    private int southHorBound;
    private double horProbability;
    private double vertProbability;

    private int horRowLight;
    private int horColLight;
    private int vertRowLight;
    private int vertColLight;

    private int numHorSquares;
    private int numVertSquares;


    /**
     * Constructs grid default values
     */
    public InterGrid() {
        MINHORLANES = 1;
        MAXHORLANES = 3;
        MINVERTLANES = 1;
        MAXVERTLANES = 4;
        MINPROB = 0;
        MAXPROB = 1;
        carSymbol = 'C';
        numHorLanes = 2;
        numVertLanes = 2;
        carLengthsPerLane = 10;
        westVertBound = carLengthsPerLane - 1;
        eastVertBound = carLengthsPerLane + numVertLanes;
        northHorBound = carLengthsPerLane - 1;
        southHorBound = carLengthsPerLane + numHorLanes;
        horProbability = 0.5;
        vertProbability = 0.5;
        horRowLight = carLengthsPerLane - 1;
        horColLight = carLengthsPerLane - 1;
        vertRowLight = carLengthsPerLane + numHorLanes;
        vertColLight = carLengthsPerLane + numVertLanes;
        numHorSquares = numHorLanes + (carLengthsPerLane * 2);
        numVertSquares = numVertLanes + (carLengthsPerLane * 2);

    }

    public char[][] getGrid() {
        return this.grid;
    }

    public int getNumHorLanes() {
        return numHorLanes;
    }

    public boolean setNumHorLanes(int numHorLanes) {
        if ((numHorLanes >= MINHORLANES) && (numHorLanes <= MAXHORLANES)) {
            this.numHorLanes = numHorLanes;
            return true;
        } else {
            return false;
        }
    }

    public int getNumVertLanes() {
        return numVertLanes;
    }

    /**
     * Set the number of vertical lanes
     *
     * @param numVertLanes is the number of vertical lanes to be set.
     * @return true OR false if numVertLanes value is within constraints.
     */
    public boolean setNumVertLanes(int numVertLanes) {
        if ((numVertLanes >= MINVERTLANES) && (numVertLanes <= MAXVERTLANES)) {
            this.numVertLanes = numVertLanes;
            return true;
        } else {
            return false;
        }
    }

    public double getHorProbability() {
        return horProbability;
    }

    /**
     * Set the probability of car entering horizontal street.
     *
     * @param horProb is the probability between 0 and 1 that a car will enter the horizontal street
     * @return true if horProb is set and between constraints. Else will return false.
     */
    public boolean setHorProbability(double horProb) {
        if ((horProb > MINPROB) && (horProb < MAXPROB)) {
            this.horProbability = horProb;
            return true;
        } else {
            return false;
        }
    }

    public double getVertProbability() {
        return vertProbability;
    }

    /**
     * Set the probability of a car entering vertical street.
     *
     * @param vertProb is the probability between 0 and 1 that a car will enter the horizontal street
     * @return true if vertProb is set and between constraints. Else will return false.
     */
    public boolean setVertProbability(double vertProb) {
        if ((vertProb > MINPROB) && (vertProb < MAXPROB)) {
            this.vertProbability = vertProb;
            return true;
        } else {
            return false;
        }
    }

    /**
     * Set element at Row, Column to the character passed in.
     *
     * @param r = Row, c = Column, ch = Character to be set
     */
    public void setElement(int r, int c, char ch) {
        this.grid[r][c] = ch;
    }

    /**
     * Takes in a Row and Column parameter and returns the corresponding character.
     *
     * @param r = Row and c = Column
     * @return Char that exists at positon [r][c] on grid.
     */
    public char getElement(int r, int c) {
        return grid[r][c];
    }

    /**
     * Print entire grid to screen.
     */
    public void displayGrid() {
        for (int i = 0; i < grid.length; i++) {
            char[] row = grid[i];
            for (int j = 0; j < row.length; j++) {
                char c = row[j];
                System.out.print(c);
            }
            System.out.println("");

        }
        System.out.println("------------------------End Simulation---------------------------");
    }

    /**
     * Initiate Grid from set details.
     */
    public void initiateGrid() {
        //Create new car list, traffic controller
        cars = new ArrayList<Car>();

        //Set intersection information
        this.numHorSquares = numHorLanes + (carLengthsPerLane * 2);
        this.numVertSquares = numVertLanes + (carLengthsPerLane * 2);
        this.westVertBound = carLengthsPerLane - 1;
        this.eastVertBound = carLengthsPerLane + numVertLanes;
        this.northHorBound = carLengthsPerLane - 1;
        this.southHorBound = carLengthsPerLane + numHorLanes;

        this.vertColStart = this.carLengthsPerLane;
        this.vertRowStart = this.numHorSquares - 1;

        this.horColStart = 0;
        this.horRowStart = this.carLengthsPerLane;

        //Set traffic light locations
        this.horRowLight = carLengthsPerLane - 2;
        this.horColLight = carLengthsPerLane - 2;
        this.vertRowLight = carLengthsPerLane + numHorLanes + 1;
        this.vertColLight = carLengthsPerLane + numVertLanes + 1;

        //Create new grid and fill with empty characters
        grid = new char[numHorSquares][numVertSquares];
        for (int r = 0; r < grid.length; r++) {
            char[] row = grid[r];
            for (int c = 0; c < row.length; c++) {
                row[c] = ' ';
            }
        }
    }

    /**
     * Sets lane boundaries and traffic lights in Grid
     */
    public void createLaneBoundaries() {
        for (int i = 0; i < carLengthsPerLane; i++) {
            //Create grass
            for (int j = 0; j < carLengthsPerLane; j++) {
                grid[i][j] = '#';
                grid[i][numVertSquares - (j + 1)] = '#';
                grid[numHorSquares - (i + 1)][j] = '#';
                grid[numHorSquares - (i + 1)][numVertSquares - (j + 1)] = '#';
            }
        }
        for (int i = 0; i < carLengthsPerLane; i++) {
            grid[i][westVertBound] = '|';
            grid[i][eastVertBound] = '|';
            grid[numHorSquares - (i + 1)][westVertBound] = '|';
            grid[numHorSquares - (i + 1)][eastVertBound] = '|';
            grid[northHorBound][numVertSquares - (i + 1)] = '-';
            grid[southHorBound][numVertSquares - (i + 1)] = '-';
            grid[northHorBound][i] = '-';
            grid[southHorBound][i] = '-';


        }
    }

    /**
     * Fills grid with empty spaces
     */
    public void eraseGrid() {
        grid = new char[numHorSquares][numVertSquares];
        for (int r = 0; r < grid.length; r++) {
            char[] row = grid[r];
            for (int c = 0; c < row.length; c++) {
                row[c] = ' ';
            }
        }
    }

    public char getCarSymbol() {
        return carSymbol;
    }

    public void setCarSymbol(char carSymbol) {
        this.carSymbol = carSymbol;
    }

    public int getVertRowLight() {
        return vertRowLight;
    }

    public int getHorColLight() {
        return horColLight;
    }

    public int getNumHorSquares() {
        return numHorSquares;
    }

    public int getHorRowStart() {
        return horRowStart;
    }

    public int getHorColStart() {
        return horColStart;
    }

    public int getVertRowStart() {
        return vertRowStart;
    }

    public int getVertColStart() {
        return vertColStart;
    }

    public ArrayList<Car> getCars() {
        return cars;
    }

    public int getHorRowLight() {
        return horRowLight;
    }

    public int getVertColLight() {
        return vertColLight;
    }

    public void setGrid(Object o) {
        grid = (char[][]) o;
    }

    public void resetCarArray() {
        cars = new ArrayList<Car>();
    }
}
